package DataFile;

import java.nio.ByteBuffer;
import java.util.LinkedList;

import ClassData.ConstantPool;
import ClassData.ConstantPoolClass_Info;
import ClassData.ConstantPoolDouble_Info;
import ClassData.ConstantPoolField_Info;
import ClassData.ConstantPoolFloat_Info;
import ClassData.ConstantPoolInfo;
import ClassData.ConstantPoolInteger_Info;
import ClassData.ConstantPoolLongValueDummy_Info;
import ClassData.ConstantPoolLong_Info;
import ClassData.ConstantPoolMethod_Info;
import ClassData.ConstantPoolName_Info;
import ClassData.ConstantPoolString_Info;
import ClassData.ConstantPoolUtf8_Info;

public class Structure_CP_Table extends Structure_Template {

	private LinkedList<Structure_CP_Constant> constantTable = 
		new LinkedList<Structure_CP_Constant>();  
	
	public  Structure_CP_Table(ConstantPool constantPool) {
		int counter;
		ConstantPoolInfo cpInfo;
		Structure_CP_Constant myConstant;
		
		for (counter=1;counter <= constantPool.size();counter++)
			{
			cpInfo=constantPool.get(counter);
			
			myConstant=parseConstant(cpInfo);
			
			if (myConstant!=null) {
				//System.out.println(myConstant.getMemorySize());
			} else {
				System.out.println("constat=null");
			}
			constantTable.add(myConstant);	
		}
	}
	
	protected int setBaseAddress(int newBaseAdress) {
		while ((newBaseAdress%4)!=0) {
			newBaseAdress++;
		}
		baseAdress=newBaseAdress;
		return(baseAdress+getMemorySize());
	}

	/**
	 * @return Elements inside Table.
	 */
	public int size() {
		return(constantTable.size());	
	}

	public int getMemorySize() {
		int mySize;
		
		mySize=SIZE_FIELD_WIDTH; // constant count
		mySize=SIZE_FIELD_WIDTH; // granularyty 4 bytes count
		mySize+=(constantTable.size()*ADRESS_WIDTH); // 
		return(mySize);
	}

	protected int getTableDataMemorySize() {		
		int mySize;
		int counter;
	
		mySize=0;
		
		for (counter=0;counter < constantTable.size();counter++) {
			mySize+=constantTable.get(counter).getMemorySize();
		}
		return(mySize);
	}

	public String getClassName(int index) {
		String ClassName;
		ClassName="";
		int classIndex;
		Structure_CP_ClassInfo myClassInfo;
		Structure_CP_UTF8Info myUtf8Info;
	
		
		if (get(index).getClass().getName().equals(Structure_CP_ClassInfo.class.getName())) {
			myClassInfo=(Structure_CP_ClassInfo)get(index);
			classIndex	=myClassInfo.getClassNameIndex();
			
			if (get(classIndex).getClass().getName().equals(Structure_CP_UTF8Info.class.getName())) {
				myUtf8Info=(Structure_CP_UTF8Info)get(classIndex);
				ClassName=myUtf8Info.getString();
			}
		}
		
		return(ClassName);	
	}

	public Structure_CP_Constant parseConstant(ConstantPoolInfo cpInfo) {
	
		if (cpInfo.getClass().getName().equals(ConstantPoolClass_Info.class.getName())) {
			Structure_CP_ClassInfo myClassInfo;
			myClassInfo = new Structure_CP_ClassInfo((ConstantPoolClass_Info)cpInfo);
			return(myClassInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolDouble_Info.class.getName())) {
			Structure_CP_DoubleInfo myDoubleInfo;
			myDoubleInfo = new Structure_CP_DoubleInfo((ConstantPoolDouble_Info)cpInfo);
			return(myDoubleInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolField_Info.class.getName())) {
			Structure_CP_FieldInfo myFieldInfo;
			myFieldInfo = new Structure_CP_FieldInfo((ConstantPoolField_Info)cpInfo);
			return(myFieldInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolFloat_Info.class.getName())) {
			Structure_CP_FloatInfo myFloatInfo;
			myFloatInfo = new Structure_CP_FloatInfo((ConstantPoolFloat_Info)cpInfo);
			return(myFloatInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolInteger_Info.class.getName())) {
			Structure_CP_IntegerInfo myIntegerInfo;
			myIntegerInfo = new Structure_CP_IntegerInfo((ConstantPoolInteger_Info)cpInfo);
			return(myIntegerInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolLong_Info.class.getName())) {
			Structure_CP_LongInfo myLongInfo;
			myLongInfo = new Structure_CP_LongInfo((ConstantPoolLong_Info)cpInfo);
			return(myLongInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolMethod_Info.class.getName())) {
			Structure_CP_MethodInfo myMethodInfo;
			myMethodInfo = new Structure_CP_MethodInfo((ConstantPoolMethod_Info)cpInfo);
			return(myMethodInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolName_Info.class.getName())) {
			Structure_CP_NameInfo myNameInfo;
			myNameInfo = new Structure_CP_NameInfo((ConstantPoolName_Info)cpInfo);
			return(myNameInfo);
		}
	
		else if (cpInfo.getClass().getName().equals(ConstantPoolString_Info.class.getName())) {
			Structure_CP_StringInfo myStringInfo;
			myStringInfo = new Structure_CP_StringInfo((ConstantPoolString_Info)cpInfo);
			return(myStringInfo);
		}
		
		else if (cpInfo.getClass().getName().equals(ConstantPoolUtf8_Info.class.getName())) {
			Structure_CP_UTF8Info myUtf8Info;
			myUtf8Info = new Structure_CP_UTF8Info((ConstantPoolUtf8_Info)cpInfo);
			return(myUtf8Info);
		}	
		
		else if (cpInfo.getClass().getName().equals(ConstantPoolLongValueDummy_Info.class.getName())) {
			Structure_CP_DummyInfo myDummyInfo;
			myDummyInfo = new Structure_CP_DummyInfo();
			return(myDummyInfo);
		}	
	
		// TODO Exception	
		return(null);	
	}

	public Structure_CP_Constant get(int index) {
		return(constantTable.get(index-1));
	}

	/**
	 *  Writes data into memory file.
	 *  @author Tavin
	 *  @param fileData buffer for data 
	 */
	public void writeData(ByteBuffer fileData) {
		fileData.position(baseAdress-DataFileCreator.BASE_MEMORY_ADRESS);
		
		fileData.putShort((short)constantTable.size());        //  2 Bytes: Size
		fileData.putShort((short)0);                           //  2 Bytes: Dummy
		
		for (Structure_CP_Constant constant : constantTable) { // size() x
			fileData.putInt(constant.getBaseAddress());        //  4 Bytes: BaseAddress
		}
		
		for (Structure_CP_Constant constant : constantTable) {
			constant.writeData(fileData);
		}

//		int counter;
//		
//		fileData.position(baseAdress-DataFileCreator.BASE_MEMORY_ADRESS);
//		
//		fileData.putShort((short)constantTable.size());                   //  2 Bytes
//		fileData.putShort((short)0);                                      //  2 Bytes
//		
//		for (counter=0;counter<constantTable.size();counter++) {
//			fileData.putInt(constantTable.get(counter).getBaseAddress()); //  4 Bytes * size
//		}
//	
//		for (counter=0;counter<constantTable.size();counter++) {
//			constantTable.get(counter).writeData(fileData);
//		}
		
	}
	
}
